﻿// CassandraConnectionConfig and CassandraConnectionConfigBuilder must be in sync
// when adding/changing properties.
// This file contains all changes needed to add/change properties for the two classes.
// Please make sure to go through all of this file when adding/changing properties.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data.Common;
using System.Linq;
using System.Text;
using Apache.Cassandra;

namespace Cassandraemon
{
	public partial class CassandraConnectionConfig
	{
		#region Constructors

        internal CassandraConnectionConfig(
            string[] hosts,
            int port,
            string keyspace)
        {
            this._Hosts = hosts;
            this._Port = port;
            this._Keyspace = keyspace;

            this._ConsistencyLevel = ConsistencyLevel.ONE;
            this._RetryCount = -1;
            this._IsFramed = true;
            this._Timeout = TimeSpan.FromMilliseconds(10000);
            this._MinPoolCountPerHost = 2;
            this._MaxPoolCountPerHost = int.MaxValue;
        }

		public CassandraConnectionConfig(
			CassandraConnectionConfig defaultValues,
			IDictionary properties)
		{
			this._Hosts = CassandraConnectionConfigBuilder.GetValueOrDefault(
				properties, "Hosts", defaultValues._Hosts);
			this._Port = CassandraConnectionConfigBuilder.GetValueOrDefault(
				properties, "Port", defaultValues._Port);
			this._Keyspace = CassandraConnectionConfigBuilder.GetValueOrDefault(
				properties, "Keyspace", defaultValues._Keyspace);
			this._ConsistencyLevel = CassandraConnectionConfigBuilder.GetValueOrDefault(
				properties, "ConsistencyLevel", defaultValues._ConsistencyLevel);
			this._RetryCount = CassandraConnectionConfigBuilder.GetValueOrDefault(
				properties, "RetryCount", defaultValues._RetryCount);
			this._IsFramed = CassandraConnectionConfigBuilder.GetValueOrDefault(
				properties, "IsFramed", defaultValues._IsFramed);
			this._Timeout = CassandraConnectionConfigBuilder.GetValueOrDefault(
				properties, "Timeout", defaultValues._Timeout);
			this._MinPoolCountPerHost = CassandraConnectionConfigBuilder.GetValueOrDefault(
				properties, "MinPoolCountPerHost", defaultValues._MinPoolCountPerHost);
			this._MaxPoolCountPerHost = CassandraConnectionConfigBuilder.GetValueOrDefault(
				properties, "MaxPoolCountPerHost", defaultValues._MaxPoolCountPerHost);
			this._Node = CassandraConnectionConfigBuilder.GetValueOrDefault(
				properties, "Node", defaultValues._Node);
		}

		#endregion

		#region Fields

		readonly string[] _Hosts;
		readonly int _Port;
		readonly string _Keyspace;
		readonly ConsistencyLevel _ConsistencyLevel;
		readonly int _RetryCount;
		readonly bool _IsFramed;
		readonly TimeSpan _Timeout;
		readonly int _MinPoolCountPerHost;
		readonly int _MaxPoolCountPerHost;
		readonly string _Node;

		#endregion

		#region Properties

		public string[] Hosts { get { return this._Hosts; } }
		public int Port { get { return this._Port; } }
		public string Keyspace { get { return this._Keyspace; } }
		public ConsistencyLevel ConsistencyLevel { get { return this._ConsistencyLevel; } }
		public int RetryCount { get { return this._RetryCount; } }
		public bool IsFramed { get { return this._IsFramed; } }
		public TimeSpan Timeout { get { return this._Timeout; } }
		public int MinPoolCountPerHost { get { return this._MinPoolCountPerHost; } }
		public int MaxPoolCountPerHost { get { return this._MaxPoolCountPerHost; } }
		public string Node { get { return this._Node; } }

		#endregion

		#region Equals

		internal bool EqualsPoolKeysExceptHosts(CassandraConnectionConfig x)
		{
			return
				this._Port == x._Port &&
				this._Keyspace == x._Keyspace &&
				this._IsFramed == x._IsFramed &&
				this._Timeout == x._Timeout &&
				this._MinPoolCountPerHost == x._MinPoolCountPerHost &&
				this._MaxPoolCountPerHost == x._MaxPoolCountPerHost &&
				this._Node == x._Node;
		}

		static readonly PoolKeyComparerImpl _PoolKeyComparerImpl = new PoolKeyComparerImpl();

		internal static IEqualityComparer<CassandraConnectionConfig> PoolKeyComparer
		{
			get { return _PoolKeyComparerImpl; }
		}

		private class PoolKeyComparerImpl : IEqualityComparer<CassandraConnectionConfig>
		{
			public bool Equals(CassandraConnectionConfig x, CassandraConnectionConfig y)
			{
				if (object.ReferenceEquals(x, y)) { return true; }
				if (x == null || y ==  null) { return false; }
				return
					x._Hosts.SetEquals(y._Hosts) &&
					x._Port == y._Port &&
					x._Keyspace == y._Keyspace &&
					x._IsFramed == y._IsFramed &&
					x._Timeout == y._Timeout &&
					x._MinPoolCountPerHost == y._MinPoolCountPerHost &&
					x._MaxPoolCountPerHost == y._MaxPoolCountPerHost &&
					x._Node == y._Node;
			}

			public int GetHashCode(CassandraConnectionConfig obj)
			{
				var value =
					obj._Hosts
						.OrderBy(item => item)
						.Aggregate(0, (seed, item) => seed ^ item.GetHashCode()) ^
					obj._Port.GetHashCode() ^
					obj._Keyspace.GetHashCode() ^
					obj._IsFramed.GetHashCode() ^
					obj._Timeout.GetHashCode() ^
					obj._MinPoolCountPerHost.GetHashCode() ^
					obj._MaxPoolCountPerHost.GetHashCode();
				if (obj._Node != null) { value ^= obj._Node.GetHashCode(); }
				return value;
			}
		}

		#endregion
	}

	public partial class CassandraConnectionConfigBuilder
	{
		public CassandraConnectionConfigBuilder(CassandraConnectionConfig config) {
			this.SetValue("Hosts", config.Hosts);
			this.SetValue("Port", config.Port);
			this.SetValue("Keyspace", config.Keyspace);
			this.SetValue("ConsistencyLevel", config.ConsistencyLevel);
			this.SetValue("RetryCount", config.RetryCount);
			this.SetValue("IsFramed", config.IsFramed);
			this.SetValue("Timeout", config.Timeout);
			this.SetValue("MinPoolCountPerHost", config.MinPoolCountPerHost);
			this.SetValue("MaxPoolCountPerHost", config.MaxPoolCountPerHost);
		}

		public string[] Hosts {
			get { return GetValueOrDefault(this, "Hosts", default(string[])); }
			set { SetValue("Hosts", value); }
		}

		public int Port {
			get { return GetValueOrDefault(this, "Port", default(int)); }
			set { SetValue("Port", value); }
		}

		public string Keyspace {
			get { return GetValueOrDefault(this, "Keyspace", default(string)); }
			set { SetValue("Keyspace", value); }
		}

		public ConsistencyLevel ConsistencyLevel {
			get { return GetValueOrDefault(this, "ConsistencyLevel", default(ConsistencyLevel)); }
			set { SetValue("ConsistencyLevel", value); }
		}

		public int RetryCount {
			get { return GetValueOrDefault(this, "RetryCount", default(int)); }
			set { SetValue("RetryCount", value); }
		}

		public bool IsFramed {
			get { return GetValueOrDefault(this, "IsFramed", default(bool)); }
			set { SetValue("IsFramed", value); }
		}

		public TimeSpan Timeout {
			get { return GetValueOrDefault(this, "Timeout", default(TimeSpan)); }
			set { SetValue("Timeout", value); }
		}

		public int MinPoolCountPerHost {
			get { return GetValueOrDefault(this, "MinPoolCountPerHost", default(int)); }
			set { SetValue("MinPoolCountPerHost", value); }
		}

		public int MaxPoolCountPerHost {
			get { return GetValueOrDefault(this, "MaxPoolCountPerHost", default(int)); }
			set { SetValue("MaxPoolCountPerHost", value); }
		}

		public string Node
		{
			get { return GetValueOrDefault(this, "Node", default(string)); }
			set { SetValue("Node", value); }
		}
	}
}
